package com.adan.auditlog.handler;

import com.alibaba.fastjson.JSONObject;
import com.adan.auditlog.annotation.AuditModelProperty;
import com.adan.auditlog.entity.DBOperationLog;
import com.adan.auditlog.entity.HandlerParam;
import com.adan.auditlog.entity.SqlCommandType;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.text.MessageFormat;
import java.util.Arrays;
import java.util.Objects;

/**
 * 数据库实体更新处理器
 *
 * @see com.baomidou.mybatisplus.core.mapper.BaseMapper#updateById(Object)
 */
@Component
@Slf4j
public class AuditUpdateEntityByIdHandler extends AbstractAuditHandler {

	@Override
	public boolean matchMethod(String methodName) {
		return methodName.startsWith(SqlCommandType.UPDATE);
	}

	@Override
	public Object doHandle(HandlerParam param, DBOperationLog pLog) throws Throwable {
		Object[] args = param.getProceedingJoinPoint().getArgs();

		Object beforeValue = beforeOperate(args, param.getProxyClass(), pLog);
		pLog.setBeforeValue(JSONObject.toJSONString(beforeValue));
		Integer result = (Integer) param.getProceedingJoinPoint().proceed();
		// 执行成功
		if (result > 0) {
			String afterValue = afterOperate(pLog, args);
			pLog.setAfterValue(afterValue);
		}
		String changeValue = getChangeValue(pLog.getAfterValue(), pLog.getBeforeValue());
		pLog.setChangeValue(changeValue);
		sqlLogMapper.insert(pLog);
		return result;
	}

	private String getChangeValue(String afterValue, String beforeValue) {
		try {
			if(StringUtils.isBlank(afterValue) || StringUtils.isBlank(beforeValue))         {
				return null;
			}
			JSONObject bJ = JSONObject.parseObject(beforeValue);
			JSONObject aJ = JSONObject.parseObject(afterValue);
			StringBuilder sbChanges = new StringBuilder();
			Field[] fields = beforeValue.getClass().getDeclaredFields();
			if (Objects.nonNull(aJ)) {
				aJ.forEach((k, v) -> {
					if (v != null && !v.equals(bJ.get(k))) {
						Field field = Arrays.stream(fields).filter(f -> f.getName().equalsIgnoreCase(k)).findFirst().orElse(null);
						if (field != null) {
							AuditModelProperty auditModelProperty = field.getAnnotation(AuditModelProperty.class);
							sbChanges.append(MessageFormat.format("{2}->修改前:{0} 修改后:{1}\n", bJ.get(k), v, auditModelProperty == null ? k : auditModelProperty.value()));
						} else {
							sbChanges.append(MessageFormat.format("{2}->修改前:{0} 修改后:{1}\n", bJ.get(k), v, k));
						}
					}
				});
			}
			return sbChanges.toString();
		} catch (Exception ex) {
			log.error("", ex);
		}
		return null;
	}
}
